package com.ctg.itrdc.sysmgr.portal.service.impl;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;

import javax.annotation.Resource;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import com.ctg.itrdc.pasp.context.service.BaseService;
import com.ctg.itrdc.sysmgr.portal.api.dto.FuncMenuDTO;
import com.ctg.itrdc.sysmgr.portal.api.service.IFuncMenuService;
import com.ctg.itrdc.sysmgr.portal.common.constant.DictEnum;
import com.ctg.itrdc.sysmgr.portal.common.constant.PrivGrantEnum;
import com.ctg.itrdc.sysmgr.portal.data.IFuncMenuDao;
import com.ctg.itrdc.sysmgr.portal.data.IPrivFuncRelDao;
import com.ctg.itrdc.sysmgr.portal.data.IPrivilegeDao;
import com.ctg.itrdc.sysmgr.portal.data.ISystemRolesDao;
import com.ctg.itrdc.sysmgr.portal.data.entity.FuncMenu;
import com.ctg.itrdc.sysmgr.portal.data.entity.PrivFuncRel;
import com.ctg.itrdc.sysmgr.portal.data.entity.Privilege;
import com.ctg.itrdc.sysmgr.portal.data.vo.FuncMenuVO;
import com.ctg.itrdc.sysmgr.portal.service.exception.SysmgrServiceException;
import com.ctg.itrdc.sysmgr.portal.service.utils.BeanUtils;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;

@Component("funcMenuService")
public class FuncMenuServiceImpl extends BaseService<FuncMenu, Long, FuncMenuDTO>
		implements IFuncMenuService, PrivGrantEnum, DictEnum {

	@Resource
	private IFuncMenuDao funcMenuDao;
	@Resource
	private ISystemRolesDao systemRolesDao;
	@Resource
	private IPrivilegeDao privilegeDao;
	@Resource
	private IPrivFuncRelDao privFuncRelDao;

	@Transactional
	@Override
	public Long insert(FuncMenuDTO dto) {
		FuncMenuDTO tmp = new FuncMenuDTO();
		tmp.setMenuName(dto.getMenuName());
		tmp.setParMenuId(dto.getParMenuId());
		tmp.setSysCode(dto.getSysCode());
		if (exists(tmp)) {
			throw new SysmgrServiceException("同父级，子菜单不能同名！");
		}
		// 插入 func_menu
		Long i = super.insert(dto);
		dto.setMenuId(i);
		insertPriAndPriFuncRel(dto);
		return i;
	}
	
	@Override
	public int updateByPrimaryKey(FuncMenuDTO dto) {
		Integer i = super.updateByPrimaryKey(dto);
		PrivFuncRel privFuncRel = new PrivFuncRel();
		privFuncRel.setPrivRefId(dto.getId());
		privFuncRel.setPrivRefType(PrivRefType.MENU.toString());
		List<PrivFuncRel> privFuncRelList = privFuncRelDao.selectByExample(privFuncRel);
		if (CollectionUtils.isNotEmpty(privFuncRelList)) {
			for (PrivFuncRel pfr : privFuncRelList) {
				Long privId = pfr.getPrivId();
				// 更新 privilege
				Privilege privilege = new Privilege();
				privilege.setPrivId(privId);
				privilege.setPrivName(dto.getMenuName());
				// DTOHelper.initDTO(dto, privilege);
				privilegeDao.updateByPrimaryKey(privilege);
			}
		} else {
			// 没有的情况重新插入
			FuncMenuDTO tmp = super.selectByPrimaryKey(dto);
			insertPriAndPriFuncRel(tmp);
		}
		return i;
	}

	@Transactional
	@Override
	public int deleteByPrimaryKey(FuncMenuDTO dto) {
		// 删除priv_func_rel和privilege的操作通过aop的方式进行。
		// 由于privilege的删除均是在func_menu或者func_comp删除的情况下进行，
    	// 因此privilege的删除无需再增加事务
		// 删除 func_menu
		Integer i = super.deleteByPrimaryKey(dto);
		return i;
	}

	@Transactional
	@Override
	public int[] batchDeleteByPrimaryKey(List<FuncMenuDTO> dtoList) {
		// 删除priv_func_rel和privilege的操作通过aop的方式进行。
		// 由于privilege的删除均是在func_menu或者func_comp删除的情况下进行，
    	// 因此privilege的删除无需再增加事务
		// 删除 func_menu
		List<FuncMenu> entities = BeanUtils.copyListNotException(dtoList, FuncMenu.class);
		return funcMenuDao.jdbcBatchDeleteByPrimary(entities);
	}

	@Override
	public List<FuncMenuDTO> selectMenuTree(Long sysUserId, Long sysPostId, FuncMenuDTO funcMenuDTO) {
		List<FuncMenuDTO> resultList = selectMenuList(sysUserId, sysPostId, funcMenuDTO);
		Collections.sort(resultList);
		return selectMenuTree(Sets.newLinkedHashSet(resultList));
	}

	@Override
	public List<FuncMenuDTO> selectSubMenuList(String grantObjType, Long grantObjId, FuncMenuDTO funcMenuDTO) {
		List<FuncMenuDTO> dtoList = this.selectByIds(null, funcMenuDTO);
		if (StringUtils.isNotBlank(grantObjType) && grantObjId != null) {
			GrantSysobjType type = GrantSysobjType.valueOf(grantObjType);
			List<FuncMenuDTO> hadMenuList = this.selectByIds(type, funcMenuDTO, grantObjId);
			for (FuncMenuDTO menu : dtoList) { // TODO 性能问题，待改进
				menu.setHadPriv(false);
				for (FuncMenuDTO had : hadMenuList) {
					if (menu.getMenuId().equals(had.getMenuId())) {
						menu.setHadPriv(true);
						menu.setPrivGrantId(had.getPrivGrantId());
					}
				}
			}
		}
		return dtoList;
	}

	@Override
	public List<FuncMenuDTO> selectSubMenuList(Long sysUserId, Long sysPostId, FuncMenuDTO funcMenuDTO) {

		List<FuncMenuDTO> dtoList = selectMenuList(sysUserId, sysPostId, funcMenuDTO);
		for (FuncMenuDTO result : dtoList) {
			FuncMenuDTO tmp = new FuncMenuDTO();
			tmp.setParMenuId(result.getMenuId().longValue());
			if (CollectionUtils.isNotEmpty(selectMenuList(sysUserId, sysPostId, tmp))) {
				result.setHasChildren(true);
			} else {
				result.setHasChildren(false);
			}
		}
		return dtoList;
	}

	@Override
	public List<FuncMenuDTO> selectMenuList(Long sysUserId, Long sysPostId, FuncMenuDTO funcMenuDTO) {
		List<FuncMenuDTO> dtoList = Lists.newArrayList();
		List<FuncMenuDTO> sysUserMenu = selectMenuListBySysUserId(sysUserId, funcMenuDTO);
		List<FuncMenuDTO> sysPostMenu = selectMenuListBySysPostId(sysPostId, funcMenuDTO);
		if (CollectionUtils.isNotEmpty(sysUserMenu))
			dtoList.addAll(sysUserMenu);
		if (CollectionUtils.isNotEmpty(sysPostMenu))
			dtoList.addAll(sysPostMenu);
		return dtoList;
	}

	@Override
	public List<FuncMenuDTO> selectByIds(GrantSysobjType sysobjType, FuncMenuDTO dto, Long... ids) {
		FuncMenu menu = null;
		if (dto != null)
			menu = BeanUtils.applyIfNotException(dto, FuncMenu.class);
		List<FuncMenuVO> voList = funcMenuDao.selectByIds(sysobjType, menu, ids);
		return BeanUtils.copyListNotException(voList, FuncMenuDTO.class);
	}

	private List<FuncMenuDTO> selectMenuListBySysUserId(Long sysUserId, FuncMenuDTO dto) {
		Set<FuncMenuVO> entitySet = Sets.newHashSet();
		Long[] roleIds = systemRolesDao.selectRoleIdsBySysUserId(sysUserId);
		List<FuncMenuVO> sysRoleMenus = null;
		List<FuncMenuVO> sysUserMenus = null;
		FuncMenu entity = BeanUtils.applyIfNotException(dto, FuncMenu.class);
		if (roleIds != null && roleIds.length > 0) {
			sysRoleMenus = funcMenuDao.selectByIds(GrantSysobjType.SYSTEM_ROLE, entity, roleIds);
			entitySet.addAll(sysRoleMenus);
		}
		sysUserMenus = funcMenuDao.selectByIds(GrantSysobjType.SYSTEM_USER, entity, sysUserId);
		entitySet.addAll(sysUserMenus);
		return BeanUtils.copyListNotException(Lists.newArrayList(entitySet), FuncMenuDTO.class);
	}

	private List<FuncMenuDTO> selectMenuListBySysPostId(Long sysPostId, FuncMenuDTO dto) {
		List<FuncMenuVO> entityList = Lists.newArrayList();
		Long[] roleIds = systemRolesDao.selectRoleIdsBySysPostId(sysPostId);
		List<FuncMenuVO> sysRoleMenus = null;
		List<FuncMenuVO> sysPostMenus = null;
		FuncMenu entity = BeanUtils.applyIfNotException(dto, FuncMenu.class);
		if (roleIds != null && roleIds.length > 0) {
			sysRoleMenus = funcMenuDao.selectByIds(GrantSysobjType.SYSTEM_ROLE, entity, roleIds);
			entityList.addAll(sysRoleMenus);
		}
		sysPostMenus = funcMenuDao.selectByIds(GrantSysobjType.SYSTEM_POST, entity, sysPostId);
		entityList.addAll(sysPostMenus);
		return BeanUtils.copyListNotException(entityList, FuncMenuDTO.class);
	}

	/**
	 * 获取菜单树
	 * 
	 * @param dtoList
	 * @return
	 */
	private List<FuncMenuDTO> selectMenuTree(Set<FuncMenuDTO> dtoList) {
		List<FuncMenuDTO> result = new ArrayList<>();
		for (FuncMenuDTO main : dtoList) {
			if (main.getParMenuId() == null || main.getParMenuId() == 0) {
				selectSubMenu(main, dtoList);
				result.add(main);
			}
		}

		return result;
	}

	/**
	 * 获取子菜单
	 * 
	 * @param main
	 * @param dtoList
	 */
	private void selectSubMenu(FuncMenuDTO main, Set<FuncMenuDTO> dtoList) {
		long menuId = main.getMenuId() == null ? -1 : main.getMenuId().longValue();
		List<FuncMenuDTO> item = new ArrayList<>();
		for (FuncMenuDTO sub : dtoList) {
			if (sub.getParMenuId() == menuId) {
				selectSubMenu(sub, dtoList); // 递归获取
				item.add(sub);
			}
		}
		if (item.size() > 0)
			main.setItem(item);
	}

	private void insertPriAndPriFuncRel(FuncMenuDTO dto) {
		// 插入 privilege
		Privilege privilege = new Privilege();
		privilege.setPrivName(dto.getMenuName());
		privilege.setStatusCd(StatusCd.S0A.toString());
		// DTOHelper.initDTO(dto, privilege);
		long x = privilegeDao.insert(privilege);
		// 插入 priv_func_rel
		PrivFuncRel privFuncRel = new PrivFuncRel();
		privFuncRel.setPrivId(x);
		privFuncRel.setPrivRefId(dto.getMenuId().longValue());
		privFuncRel.setPrivRefType(PrivRefType.MENU.toString());
		privFuncRel.setStatusCd(StatusCd.S0A.toString());
		// DTOHelper.initDTO(dto, privFuncRel);
		privFuncRelDao.insert(privFuncRel);
	}

}
